var Collection = function(data){
    if (data && !(data instanceof Array)) return;
    /***
     * @private
     */
    this.data = data || new Array();

    /***
     *@private
     */
    this.events = new Object();
    /***
     *@private
     */
    this.owner = new Object();

    /***
     * Adiciona o elemento no fim do Array e retorna a instancia do objeto
     * @param obj
     * @return ArrayCollection
     */
    this.push = function(obj) {
        this.data.push(obj);
        this.fire(CollectionEvent.DATA_CHANGED);
        return this;
    }

    /***
     * Adiciona o elemento no início do Array e retorna a instancia do objeto
     * @param obj
     * @return ArrayCollection
     */
    this.unshift = function(obj) {
        this.data.push(obj);
        this.fire(CollectionEvent.DATA_CHANGED);
        return this;
    }

    /***
     * Remove e retorna o primeiro item do Array
     * @return Object
     */
    this.shift = function() {
        var shifted = this.data.shift();
        this.fire(CollectionEvent.DATA_CHANGED);
        return shifted;
    }

    /***
     * Remove e retorna o ultimo item do Array
     * @return Object
     */
    this.pop = function() {
        var poped = this.data.pop();
        this.fire(CollectionEvent.DATA_CHANGED);
        return poped;
    }

    /***
     * Remove e retorna um ou mais itens do array de acordo com a(s) posição(ões) indicada(s)
     * Também pode substituir o(s) valore(s) na(s) posiçõe(s) indicada(s) pelo terceiro parametro
     * @return ArrayCollction
     */
    this.splice = function(index, length, replacement) {
        var spliced = (replacement) ? this.data.splice(index,length,replacement) : this.data.splice(index,length);
        this.fire(CollectionEvent.DATA_CHANGED);
        return spliced;
    }

    /***
     * Apenas retorna um ou mais itens do array de acordo com a(s) posição(ões) indicada(s)
     * Também pode substituir o(s) valore(s) na(s) posiçõe(s) indicada(s) pelo terceiro parametro
     * @return ArrayCollction
     */
    this.slice = function(index, length, replacement) {
        var sliced = (replacement) ? this.data.splice(index,length,replacement) : this.data.splice(index,length);
        this.fire(CollectionEvent.DATA_CHANGED);
        return sliced;
    }

    /***
     * Adiciona um evento à instancia do objeto
     * @param eventName
     * @param callBack
     * @return ArrayCollection
     * @example
     * function dataChangedHandler(event) {
     *      alert("Data Changed!");
     * }
     * var myCollection = new Collection();
     *     myCollection.bind(CollectionEvent.DATA_CHANGED, dataChangedHandler);
     *     myCollection.push({ data : 'my data' });
     */
    this.bind = function(eventName, callBack) {
        if (!this.events[eventName])
        this.events[eventName] = new Array();
        this.events[eventName].push(callBack)
        return this;
    }

    /***
     * Dispara o evento indicado
     * @param eventName
     * @param eventData
     * @return ArrayCollection
     */
    this.fire = function(eventName, eventData) {
        if (this.events[eventName]) {
            for(var i = 0; i < this.events[eventName].length; i++) {
                this.events[eventName][i]({target:this, data : eventData});
            }
        }
        return this;
    }

    /***
     * Retorna o tamanho do Array
     * @return Integer
     */
    this.size = function() {
        return this.data.length;
    }

    /***
     * Retorna o item que se encontra no index indicado
     * @return Object
     */
    this.getItemAt = function(index) {
        return this.data[index];
    }

    /***
     * Retorna o objeto em forma de String
     * @return String
     */
    this.toString = function() {return "[Object ArrayCollection]";}

    this.each = function(callBack, thisObject){
        return this.data.every(callBack, thisObject);
    }
}

var CollectionEvent = {
    /**
     * Evento Disparado ao alterar os dados do <code>dataSource</code>
     * @example
     * function dataChangedHandler(event) {
     *      alert("Data Changed!");
     * }
     * var myCollection = new Collection();
     *     myCollection.bind(CollectionEvent.DATA_CHANGED, dataChangedHandler);
     *     myCollection.push({ data : 'my data' });
     * 
     * @eventType CollectionEvent.DATA_CHANGED
     */
    DATA_CHANGED : "dataChanged="
}